/*     */ package com.zimbra.cs.service.authenticator;
/*     */ 
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import java.io.FileInputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.PrintStream;
/*     */ import java.io.PrintWriter;
/*     */ import java.math.BigInteger;
/*     */ import java.security.cert.CertificateFactory;
/*     */ import java.security.cert.CertificateParsingException;
/*     */ import java.security.cert.X509Certificate;
/*     */ import java.util.Collection;
/*     */ import java.util.Date;
/*     */ import java.util.HashMap;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import javax.naming.InvalidNameException;
/*     */ import javax.naming.ldap.LdapName;
/*     */ import javax.naming.ldap.Rdn;
/*     */ import javax.security.auth.x500.X500Principal;
/*     */ import org.apache.commons.cli.CommandLine;
/*     */ import org.apache.commons.cli.CommandLineParser;
/*     */ import org.apache.commons.cli.GnuParser;
/*     */ import org.apache.commons.cli.HelpFormatter;
/*     */ import org.apache.commons.cli.Options;
/*     */ import org.apache.commons.cli.ParseException;
/*     */ import org.bouncycastle.asn1.ASN1InputStream;
/*     */ import org.bouncycastle.asn1.ASN1Object;
/*     */ import org.bouncycastle.asn1.ASN1ObjectIdentifier;
/*     */ import org.bouncycastle.asn1.ASN1OctetString;
/*     */ import org.bouncycastle.asn1.ASN1TaggedObject;
/*     */ import org.bouncycastle.asn1.DEREncodable;
/*     */ import org.bouncycastle.asn1.DERIA5String;
/*     */ import org.bouncycastle.asn1.DERObjectIdentifier;
/*     */ import org.bouncycastle.asn1.DEROctetString;
/*     */ import org.bouncycastle.asn1.DERSequence;
/*     */ import org.bouncycastle.asn1.DERUTF8String;
/*     */ import org.bouncycastle.asn1.x509.CRLDistPoint;
/*     */ import org.bouncycastle.asn1.x509.DistributionPoint;
/*     */ import org.bouncycastle.asn1.x509.DistributionPointName;
/*     */ import org.bouncycastle.asn1.x509.GeneralName;
/*     */ import org.bouncycastle.asn1.x509.GeneralNames;
/*     */ import org.bouncycastle.asn1.x509.X509Extension;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class CertUtil
/*     */ {
/*     */   static final String LOG_PREFIX = "certauth - ";
/*     */   static final String ATTR_EMAILADDRESS = "EMAILADDRESS";
/*     */   private static final String OID_UPN = "1.3.6.1.4.1.311.20.2.3";
/*  85 */   private static final Map<String, String> KNOWN_NON_RFC2252_ATTRS = new HashMap();
/*     */   X509Certificate cert;
/*     */   
/*  88 */   static { KNOWN_NON_RFC2252_ATTRS.put("EMAILADDRESS", "1.2.840.113549.1.9.1"); }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   CertUtil(X509Certificate cert)
/*     */   {
/*  97 */     this.cert = cert;
/*     */   }
/*     */   
/*     */   String getCertField(ClientCertPrincipalMap.CertField certField) {
/* 101 */     if ((certField instanceof ClientCertPrincipalMap.KnownCertField))
/* 102 */       return getKnownCertField((ClientCertPrincipalMap.KnownCertField)certField);
/* 103 */     if ((certField instanceof ClientCertPrincipalMap.SubjectCertField)) {
/* 104 */       return getSubjectCertField((ClientCertPrincipalMap.SubjectCertField)certField);
/*     */     }
/* 106 */     return null;
/*     */   }
/*     */   
/*     */   private String getKnownCertField(ClientCertPrincipalMap.KnownCertField certField) {
/* 110 */     String value = null;
/*     */     
/* 112 */     switch (certField.getField()) {
/*     */     case SUBJECT_DN: 
/* 114 */       value = getSubjectDN();
/* 115 */       break;
/*     */     case SUBJECTALTNAME_OTHERNAME_UPN: 
/* 117 */       value = getSubjectAltNameOtherNameUPN();
/* 118 */       break;
/*     */     case SUBJECTALTNAME_RFC822NAME: 
/* 120 */       value = getSubjectAltNameRfc822Name();
/*     */     }
/*     */     
/* 123 */     return value;
/*     */   }
/*     */   
/*     */   private String getSubjectCertField(ClientCertPrincipalMap.SubjectCertField certField) {
/* 127 */     String rdnAttrType = certField.getRDNAttrType();
/* 128 */     return getSubjectAttr(rdnAttrType, (String)KNOWN_NON_RFC2252_ATTRS.get(rdnAttrType));
/*     */   }
/*     */   
/*     */   String getSubjectDN() {
/* 132 */     X500Principal subjectPrincipal = this.cert.getSubjectX500Principal();
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 145 */     return subjectPrincipal.getName();
/*     */   }
/*     */   
/*     */   String getSubjectAltNameOtherNameUPN() {
/* 149 */     Collection<List<?>> generalNames = null;
/*     */     try {
/* 151 */       generalNames = this.cert.getSubjectAlternativeNames();
/*     */     } catch (CertificateParsingException e) {
/* 153 */       ZimbraLog.account.warn("certauth - unable to get subject alternative names", e);
/*     */     }
/*     */     
/* 156 */     if (generalNames == null) {
/* 157 */       return null;
/*     */     }
/*     */     
/* 160 */     ASN1InputStream decoder = null;
/*     */     try
/*     */     {
/* 163 */       for (List<?> generalName : generalNames) {
/* 164 */         Integer tag = (Integer)generalName.get(0);
/* 165 */         if (0 == tag.intValue())
/*     */         {
/* 167 */           decoder = new ASN1InputStream((byte[])generalName.toArray()[1]);
/* 168 */           DEREncodable encoded = decoder.readObject();
/* 169 */           DERSequence derSeq = (DERSequence)encoded;
/*     */           
/* 171 */           DERObjectIdentifier typeId = DERObjectIdentifier.getInstance(derSeq.getObjectAt(0));
/* 172 */           String oid = typeId.getId();
/*     */           
/* 174 */           String value = null;
/* 175 */           ASN1TaggedObject otherNameValue = ASN1TaggedObject.getInstance(derSeq.getObjectAt(1));
/* 176 */           if ("1.3.6.1.4.1.311.20.2.3".equals(oid)) {
/* 177 */             ASN1TaggedObject upnValue = ASN1TaggedObject.getInstance(otherNameValue.getObject());
/* 178 */             DERUTF8String str = DERUTF8String.getInstance(upnValue.getObject());
/* 179 */             value = str.getString();
/* 180 */             return value;
/*     */           }
/*     */         }
/*     */       }
/*     */     } catch (IOException e) {
/* 185 */       ZimbraLog.account.warn("certauth - unable to process ASN.1 data", e);
/*     */     } finally {
/* 187 */       ByteUtil.closeStream(decoder);
/*     */     }
/*     */     
/* 190 */     return null;
/*     */   }
/*     */   
/*     */   String getSubjectAltNameRfc822Name() {
/* 194 */     Collection<List<?>> generalNames = null;
/*     */     try {
/* 196 */       generalNames = this.cert.getSubjectAlternativeNames();
/*     */     } catch (CertificateParsingException e) {
/* 198 */       ZimbraLog.account.warn("certauth - unable to get subject alternative names", e);
/*     */     }
/*     */     
/* 201 */     if (generalNames == null) {
/* 202 */       return null;
/*     */     }
/*     */     
/* 205 */     for (List<?> generalName : generalNames) {
/* 206 */       Integer tag = (Integer)generalName.get(0);
/* 207 */       if (1 == tag.intValue()) {
/* 208 */         String value = (String)generalName.get(1);
/* 209 */         return value;
/*     */       }
/*     */     }
/*     */     
/* 213 */     return null;
/*     */   }
/*     */   
/*     */   private String getSubjectAttr(String needAttrName, String needAttrOid) {
/* 217 */     String subjectDN = getSubjectDN();
/*     */     try
/*     */     {
/* 220 */       LdapName dn = new LdapName(subjectDN);
/* 221 */       List<Rdn> rdns = dn.getRdns();
/*     */       
/* 223 */       for (Rdn rdn : rdns) {
/* 224 */         String type = rdn.getType();
/*     */         
/* 226 */         boolean isOid = type.contains(".");
/*     */         
/* 228 */         boolean matched = isOid ? type.equals(needAttrOid) : type.equals(needAttrName);
/*     */         
/* 230 */         if (matched) {
/* 231 */           Object value = rdn.getValue();
/* 232 */           if (value != null)
/*     */           {
/*     */ 
/*     */ 
/* 236 */             if (isOid) {
/* 237 */               byte[] bytes = (byte[])value;
/* 238 */               ASN1InputStream decoder = null;
/*     */               try {
/* 240 */                 decoder = new ASN1InputStream(bytes);
/* 241 */                 DEREncodable encoded = decoder.readObject();
/* 242 */                 DERIA5String str = DERIA5String.getInstance(encoded);
/* 243 */                 return str.getString();
/*     */               } catch (IOException e) {
/* 245 */                 ZimbraLog.account.warn("certauth - unable to decode " + type, e);
/*     */               } finally {
/* 247 */                 ByteUtil.closeStream(decoder);
/*     */               }
/*     */             }
/*     */             else {
/* 251 */               return value.toString();
/*     */             } }
/*     */         }
/*     */       }
/*     */     } catch (InvalidNameException e) {
/* 256 */       ZimbraLog.account.warn("certauth - Invalid subject dn value" + subjectDN, e);
/*     */     }
/*     */     
/* 259 */     return null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private void loadCert(String certFilePath)
/*     */     throws Exception
/*     */   {
/* 271 */     InputStream inStream = new FileInputStream(certFilePath);
/* 272 */     CertificateFactory cf = CertificateFactory.getInstance("X.509");
/* 273 */     this.cert = ((X509Certificate)cf.generateCertificate(inStream));
/* 274 */     inStream.close();
/*     */   }
/*     */   
/*     */   private void dumpCert(String outputFlePath) throws Exception {
/* 278 */     outputCert(outputFlePath, true);
/*     */   }
/*     */   
/*     */   private void printCert(String outputFlePath) throws Exception {
/* 282 */     outputCert(outputFlePath, false);
/*     */   }
/*     */   
/*     */   private void outputCert(String outputFlePath, boolean dump) throws Exception {
/*     */     PrintStream outStream;
/*     */     PrintStream outStream;
/* 288 */     if (outputFlePath != null) {
/* 289 */       outStream = new PrintStream(outputFlePath);
/*     */     } else {
/* 291 */       outStream = System.out;
/*     */     }
/*     */     try
/*     */     {
/* 295 */       if (dump) {
/* 296 */         outStream.println(this.cert.toString());
/*     */       } else {
/* 298 */         printCert(outStream);
/*     */       }
/*     */     } finally {
/* 301 */       outStream.flush();
/* 302 */       if (outputFlePath != null) {
/* 303 */         outStream.close();
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void printCert(PrintStream outStream) throws Exception {
/* 309 */     printVersion(outStream);
/* 310 */     printSerialNumber(outStream);
/* 311 */     printSigAlg(outStream);
/* 312 */     printIssuer(outStream);
/* 313 */     printValidity(outStream);
/* 314 */     printSubject(outStream);
/*     */     
/* 316 */     printX509V3Extension(outStream);
/*     */   }
/*     */   
/*     */   private void printX509V3Extension(PrintStream outStream) throws Exception {
/* 320 */     outStream.println();
/* 321 */     outStream.format("X509v3 extensions:\n", new Object[0]);
/*     */     
/* 323 */     printSubjectAlternativeNames(outStream);
/* 324 */     outStream.println();
/*     */     
/* 326 */     printCRLDistributionPoints(outStream);
/* 327 */     outStream.println();
/*     */   }
/*     */   
/*     */   private void printVersion(PrintStream outStream) {
/* 331 */     int version = this.cert.getVersion();
/*     */     
/* 333 */     outStream.format("Version: %d (0x%x)\n", new Object[] { Integer.valueOf(version), Integer.valueOf(version) });
/*     */   }
/*     */   
/*     */   private void printSerialNumber(PrintStream outStream) {
/* 337 */     BigInteger serialNumber = this.cert.getSerialNumber();
/*     */     
/* 339 */     outStream.format("Serial Number: %s (0x%x)\n", new Object[] { serialNumber.toString(), serialNumber });
/*     */   }
/*     */   
/*     */   private void printSigAlg(PrintStream outStream) throws Exception {
/* 343 */     String sigAlgName = this.cert.getSigAlgName();
/* 344 */     String sigAlgOID = this.cert.getSigAlgOID();
/*     */     
/* 346 */     outStream.format("Signature Algorithm: %s (%s)\n", new Object[] { sigAlgName, sigAlgOID });
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private void printIssuer(PrintStream outStream)
/*     */   {
/* 358 */     X500Principal issuerPrincipal = this.cert.getIssuerX500Principal();
/* 359 */     outStream.format("Issuer: %s\n", new Object[] { issuerPrincipal.getName() });
/*     */   }
/*     */   
/*     */   private void printValidity(PrintStream outStream) {
/* 363 */     Date notBefore = this.cert.getNotBefore();
/* 364 */     Date notAfter = this.cert.getNotAfter();
/*     */     
/* 366 */     outStream.format("Validity\n", new Object[0]);
/* 367 */     outStream.format("    Not Before: %s\n", new Object[] { notBefore.toGMTString() });
/* 368 */     outStream.format("    Not After : %s\n", new Object[] { notAfter.toGMTString() });
/*     */   }
/*     */   
/*     */   private void printSubject(PrintStream outStream) {
/* 372 */     X500Principal subjectPrincipal = this.cert.getSubjectX500Principal();
/* 373 */     outStream.format("Subject: %s\n", new Object[] { subjectPrincipal.getName() });
/*     */   }
/*     */   
/*     */   private void printSubjectAlternativeNames(PrintStream outStream) throws Exception
/*     */   {
/* 378 */     String UPN_DISPLAY = "Principal Name";
/* 379 */     String RFC822NAME_DISPLAY = "RFC822 Name";
/* 380 */     String DNSNAME_DISPLAY = "DNS Name";
/*     */     
/* 382 */     outStream.format("X509v3 Subject Alternative Name: \n", new Object[0]);
/*     */     
/* 384 */     ASN1InputStream decoder = null;
/*     */     try {
/* 386 */       Collection<List<?>> generalNames = this.cert.getSubjectAlternativeNames();
/*     */       
/* 388 */       if (generalNames == null) {
/*     */         return;
/*     */       }
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 398 */       for (List<?> generalName : generalNames) {
/* 399 */         Integer tag = (Integer)generalName.get(0);
/* 400 */         if (0 == tag.intValue())
/*     */         {
/* 402 */           decoder = new ASN1InputStream((byte[])generalName.toArray()[1]);
/* 403 */           DEREncodable encoded = decoder.readObject();
/* 404 */           DERSequence derSeq = (DERSequence)encoded;
/*     */           
/* 406 */           DERObjectIdentifier typeId = DERObjectIdentifier.getInstance(derSeq.getObjectAt(0));
/* 407 */           String oid = typeId.getId();
/*     */           
/* 409 */           String value = null;
/* 410 */           ASN1TaggedObject otherNameValue = ASN1TaggedObject.getInstance(derSeq.getObjectAt(1));
/* 411 */           if ("1.3.6.1.4.1.311.20.2.3".equals(oid)) {
/* 412 */             ASN1TaggedObject upnValue = ASN1TaggedObject.getInstance(otherNameValue.getObject());
/* 413 */             DERUTF8String str = DERUTF8String.getInstance(upnValue.getObject());
/* 414 */             value = str.getString();
/*     */           }
/*     */           
/* 417 */           outStream.format("    [%d] %s(%s) = %s\n", new Object[] { tag, oid, "Principal Name", value });
/* 418 */         } else if (1 == tag.intValue()) {
/* 419 */           String value = (String)generalName.get(1);
/* 420 */           outStream.format("    [%d] %s = %s\n", new Object[] { tag, "RFC822 Name", value });
/* 421 */         } else if (2 == tag.intValue()) {
/* 422 */           String value = (String)generalName.get(1);
/* 423 */           outStream.format("    [%d] %s = %s\n", new Object[] { tag, "DNS Name", value });
/*     */         } else {
/* 425 */           outStream.format("    [%d] - not yet supported\n", new Object[] { tag });
/*     */         }
/*     */       }
/*     */     }
/*     */     catch (CertificateParsingException e) {
/* 430 */       e.printStackTrace();
/*     */     } finally {
/* 432 */       ByteUtil.closeStream(decoder);
/*     */     }
/*     */   }
/*     */   
/*     */   private void printCRLDistributionPoints(PrintStream outStream) throws Exception
/*     */   {
/* 438 */     outStream.format("X509v3 CRL Distribution Points: \n", new Object[0]);
/*     */     
/* 440 */     String extOid = X509Extension.cRLDistributionPoints.getId();
/* 441 */     byte[] extVal = this.cert.getExtensionValue(extOid);
/* 442 */     if (extVal == null) {
/* 443 */       return;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 462 */     byte[] extnValue = DEROctetString.getInstance(ASN1Object.fromByteArray(extVal)).getOctets();
/*     */     
/* 464 */     CRLDistPoint crlDistPoint = CRLDistPoint.getInstance(ASN1Object.fromByteArray(extnValue));
/* 465 */     DistributionPoint[] distPoints = crlDistPoint.getDistributionPoints();
/*     */     
/* 467 */     for (DistributionPoint distPoint : distPoints) {
/* 468 */       DistributionPointName distPointName = distPoint.getDistributionPoint();
/* 469 */       int type = distPointName.getType();
/*     */       
/* 471 */       if (0 == type) {
/* 472 */         outStream.format("Full Name: \n", new Object[0]);
/* 473 */         GeneralNames generalNames = GeneralNames.getInstance(distPointName.getName());
/* 474 */         GeneralName[] names = generalNames.getNames();
/* 475 */         for (GeneralName generalname : names) {
/* 476 */           int tag = generalname.getTagNo();
/* 477 */           if (6 == tag) {
/* 478 */             DEREncodable name = generalname.getName();
/* 479 */             DERIA5String str = DERIA5String.getInstance(name);
/* 480 */             String value = str.getString();
/* 481 */             outStream.format("    %s\n", new Object[] { value });
/*     */           } else {
/* 483 */             outStream.format("tag %d not yet implemented", new Object[] { Integer.valueOf(tag) });
/*     */           }
/*     */         }
/*     */       } else {
/* 487 */         outStream.format("type %d not yet implemented", new Object[] { Integer.valueOf(type) });
/*     */       }
/*     */     }
/*     */   }
/*     */   
/* 492 */   private static int EXIT_CODE_GOOD = 0;
/* 493 */   private static int EXIT_CODE_BAD = 0;
/*     */   
/* 495 */   private static String O_CERT = "c";
/* 496 */   private static String O_DUMP = "d";
/* 497 */   private static String O_GET = "g";
/* 498 */   private static String O_HELP = "h";
/* 499 */   private static String O_PRINT = "p";
/*     */   
/*     */   private static void usage(Options options, String msg) {
/* 502 */     System.out.println("\n");
/* 503 */     System.out.println(msg);
/* 504 */     usage(options);
/*     */   }
/*     */   
/*     */   private static void usage(Options options) {
/* 508 */     System.out.println("\n");
/* 509 */     PrintWriter pw = new PrintWriter(System.out, true);
/* 510 */     HelpFormatter formatter = new HelpFormatter();
/* 511 */     formatter.printHelp(pw, formatter.getWidth(), "zmjava " + CertUtil.class.getCanonicalName() + " [options]", null, options, formatter.getLeftPadding(), formatter.getDescPadding(), null);
/*     */     
/*     */ 
/* 514 */     System.out.println("\n");
/* 515 */     pw.flush();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void main(String[] args)
/*     */   {
/* 523 */     Options options = new Options();
/* 524 */     options.addOption(O_CERT, true, "file path of the certificate");
/* 525 */     options.addOption(O_DUMP, false, "dump the certificate (print toString() value of the certificate)");
/* 526 */     options.addOption(O_GET, true, "get a field in the certificate, valid fields:" + ClientCertPrincipalMap.KnownCertField.names() + "|" + ClientCertPrincipalMap.SubjectCertField.names());
/*     */     
/* 528 */     options.addOption(O_HELP, false, "print usage");
/* 529 */     options.addOption(O_PRINT, false, "print the certificate(print each parsed certificate fields)");
/*     */     
/* 531 */     CommandLine cl = null;
/*     */     try {
/* 533 */       CommandLineParser parser = new GnuParser();
/* 534 */       cl = parser.parse(options, args);
/* 535 */       if (cl == null) {
/* 536 */         throw new ParseException("");
/*     */       }
/*     */     } catch (ParseException e) {
/* 539 */       usage(options);
/* 540 */       e.printStackTrace();
/* 541 */       System.exit(EXIT_CODE_BAD);
/*     */     }
/*     */     
/* 544 */     if (cl.hasOption(O_HELP)) {
/* 545 */       usage(options);
/* 546 */       System.exit(EXIT_CODE_GOOD);
/*     */     }
/*     */     
/* 549 */     String certFilePath = null;
/*     */     
/* 551 */     if (cl.hasOption(O_CERT)) {
/* 552 */       certFilePath = cl.getOptionValue(O_CERT);
/*     */     } else {
/* 554 */       usage(options, "missing cert path");
/* 555 */       System.exit(EXIT_CODE_BAD);
/*     */     }
/*     */     try
/*     */     {
/* 559 */       CertUtil certUtil = new CertUtil();
/* 560 */       certUtil.loadCert(certFilePath);
/*     */       
/* 562 */       if (cl.hasOption(O_DUMP)) {
/* 563 */         certUtil.dumpCert((String)null);
/* 564 */       } else if (cl.hasOption(O_PRINT)) {
/* 565 */         certUtil.printCert((String)null);
/* 566 */       } else if (cl.hasOption(O_GET)) {
/* 567 */         String field = cl.getOptionValue(O_GET);
/* 568 */         ClientCertPrincipalMap.CertField certField = ClientCertPrincipalMap.parseCertField(field);
/* 569 */         String value = certUtil.getCertField(certField);
/* 570 */         System.out.println(field + ": " + value);
/*     */       }
/*     */     }
/*     */     catch (Exception e) {
/* 574 */       e.printStackTrace();
/* 575 */       System.exit(EXIT_CODE_BAD);
/*     */     }
/*     */   }
/*     */   
/*     */   private CertUtil() {}
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/authenticator/CertUtil.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */